#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <limits>
#include <stdlib.h>
#include <memory.h>
#include "Exception.h"
#include "System.h"
#include "Log.h"


namespace {
	bool littleEndian() {
		int i = 0;
		((char *)(&i))[0] = 1;
		return(i == 1);
	}

	bool bigEndian() {
		return !littleEndian();
	}
}

namespace illib {
	namespace System{
		Allocator * Allocator::instance_;
		Allocator& allocator(){
			return *Allocator::instance_;
		}
		void allocator(Allocator& allocator){
			Allocator::instance_ = &allocator;
		}
		size_t Allocator::pagesize(){
			return pagesize_;
		}
		void Allocator::initialize(size_t pagesize){
			pagesize_ = pagesize;
		}
		uint8_t * Allocator::allocate(size_t size, uint8_t alignment){
			if ((size % pagesize_) != 0) Console::print("Warning: request for wrong size %d bytes when page size is %d\n",size, pagesize_);
			void * ptr = calloc(1, size);
			if(ptr == 0) throw Exceptions::memory;
			memset(ptr, 0x11, size);
			return static_cast<uint8_t*>(ptr);
		}
		void Allocator::release(void * ptr, size_t size){
			if((ptr == 0) || (size == 0)) throw Exceptions::arguments;
			if ((size % pagesize_) != 0) Console::print("Warning: request for wrong size %d bytes when page size is %d\n",size, pagesize_);
			memset(ptr, 0xcc, size);
			free(ptr);
		}
		size_t align(size_t size, uint8_t alignment){
			if (size % alignment == 0) return size;
			uint8_t padding = alignment - (size % alignment);
			return size+padding;
		}
		const Endiannes endianness = littleEndian() ? little : big;
		const char* compiler = "";//__VERSION__;


		Memory::Memory(uint8_t* block, size_t blockSize) :
			blockSize_(blockSize), block_(static_cast<uint8_t*> (block)){
		}

		bool Memory::contains(void* ptr, size_t size) {
			uint8_t* end = static_cast<uint8_t*> (ptr) + size;
			if (ptr < block_)
				return false;
			if (end > block_+blockSize_)
				return false;
			return true;
		}

		Memory::~Memory() {
			blockSize_ = 0;
			block_ = 0;
		}
	}
}
